package penguin.masking.jdbc;

import penguin.masking.StringUtil;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author wuxh
 * @version 1.0.0
 */
public class AbstractDBMetaHandler implements DBMetaHandler {

    public ResultSetMetaData resultSetMetaData(final ResultSet set) {
        ResultSetMetaData metaData = null;
        try {
            metaData = set.getMetaData();
        } catch (Exception e) {
            throw new RuntimeException("数据库驱动不支持元数据查询！", e);
        }
        return metaData;
    }

    @Override
    public String columnName(ResultSet set, Object columnName) {
        String _c = null;
        if (columnName instanceof Integer) {
            try {
                _c = resultSetMetaData(set).getColumnName((Integer) columnName);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (StringUtil.isEmpty(_c)) {
                throw new RuntimeException("数据库驱动不支持列名查询！");
            }
            return _c;
        }
        return columnName.toString();
    }

    @Override
    public int columnIndex(ResultSet set, Object column) {
        if (column instanceof Integer) {
            Integer columnIndex = (Integer) column;
            return columnIndex == null ? -1 : columnIndex;
        } else {
            try {
                return set.findColumn(column.toString());
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return -1;
    }

    @Override
    public String tableName(ResultSet set, int columnIndex) {
        throw new RuntimeException("数据库驱动不支持表名查询！");
    }

    @Override
    public String userName(ResultSet set) {
        throw new RuntimeException("数据库驱动不支持用户名查询！");
    }

    @Override
    public String catalogName(ResultSet set, int columnIndex) {
        throw new RuntimeException("数据库驱动不支持数据库名查询！");
    }


    private final Map<String, Object> cache = new HashMap<>();

    /**
     * 回调地狱检查
     *
     * @param check
     * @param <T>
     * @return
     * @throws Exception
     */
    protected <T extends Object> T doCheck(LoopCallCheck<T> check) throws Exception {
        String hashCode = check.hashValue();
        if (!cache.containsKey(hashCode)) {
            cache.put(hashCode, null);//解决回调地狱问题
            T callValue = check.call();
            cache.put(hashCode, callValue);
            return callValue;
        }
        T cacheV = (T) cache.get(hashCode);
        if (cacheV == null) {
            return null;
        }
        return cacheV;
    }
}

abstract class LoopCallCheck<T> {

    public abstract String hashValue();

    public abstract T call() throws Exception;
}
